﻿//----------------------------------------------------------------
// Desc: 
// Edit: ShowLong, http://blog.csdn.net/showlong
//
// Date Created: 2010-06-19
//
// Update Date : 
//
// Copyright (c) Fuel4D (http://www.fuel4d.com), All rights reserved.
//
//----------------------------------------------------------------
#pragma once


#pragma pack(push, 1)


//----------------------------------------------------------------
// 2D
//----------------------------------------------------------------
struct FVERTEX2D
{
    FDECLARE_STRUCT(FVERTEX2D)

    float x, y, z, rhw;
    DWORD color;
    float u, v;

    FVERTEX2D()
        :x(0)
        ,y(0)
        ,z(0.5f)
        ,rhw(1.f)
        ,color(0xFFFFFFFF)
        ,u(0)
        ,v(0)
    {}
    FVERTEX2D(float _x, float _y, float _u, float _v, DWORD _c = 0xFFFFFFFF)
        :x(_x)
        ,y(_y)
        ,z(0.5f)
        ,rhw(1.f)
        ,color(_c)
        ,u(_u)
        ,v(_v)
    {}
    bool operator == (const FVERTEX2D& r)
    {
        return (x==r.x && y==r.y && z==r.z && rhw==r.rhw && color==r.color && u==r.u && v==r.v);
    }
};
const DWORD FVERTEX2D_STRIDE = sizeof(FVERTEX2D);
const EF_FVF FVERTEX2D_FVF = (EF_FVF)(eFVF_XYZRHW|eFVF_DIFFUSE|eFVF_TEX1);


//----------------------------------------------------------------
// 2D Line
//----------------------------------------------------------------
struct FVERTEX2D_LINE
{
    FDECLARE_STRUCT(FVERTEX2D_LINE)

    float x, y, z, rhw;
    DWORD color;

    FVERTEX2D_LINE()
        :x(0)
        ,y(0)
        ,z(0.5f)
        ,rhw(1.f)
        ,color(0xFFFFFFFF)
    {}
    bool operator == (const FVERTEX2D_LINE& r)
    {
        return (x==r.x && y==r.y && z==r.z && rhw==r.rhw && color==r.color);
    }
};
const DWORD FVERTEX2D_LINE_STRIDE = sizeof(FVERTEX2D_LINE);
const EF_FVF FVERTEX2D_LINE_FVF = (EF_FVF)(eFVF_XYZRHW|eFVF_DIFFUSE);


//----------------------------------------------------------------
// 3D sprite
//----------------------------------------------------------------
struct FVERTEX3D_SPRITE
{
    FDECLARE_STRUCT(FVERTEX3D_SPRITE)

    float x, y, z;
    DWORD color;
    float u, v;

    FVERTEX3D_SPRITE()
        :x(0)
        ,y(0)
        ,z(0)
        ,color(0xFFFFFFFF)
        ,u(0)
        ,v(0)
    {}
    bool operator == (const FVERTEX3D_SPRITE& r)
    {
        //return (x==r.x && y==r.y && z==r.z && nx==r.nx && ny==r.ny && nz==r.nz && color==r.color && u==r.u && v==r.v);
        if (fabsf(x  - r.x ) > 0.01f)
            return false;
        if (fabsf(y  - r.y ) > 0.01f)
            return false;
        if (fabsf(z  - r.z ) > 0.01f)
            return false;
        // UV要求严格，否则会产生撕裂
        return (color == r.color && u == r.u && v == r.v);
    }
};
const DWORD FVERTEX3D_SPRITE_STRIDE = sizeof(FVERTEX3D_SPRITE);
const EF_FVF FVERTEX3D_SPRITE_FVF = (EF_FVF)(eFVF_XYZ|eFVF_DIFFUSE|eFVF_TEX1);


//----------------------------------------------------------------
// 3D Line
//----------------------------------------------------------------
struct FVERTEX3D_LINE
{
    FDECLARE_STRUCT(FVERTEX3D_LINE)

    float x, y, z;
    DWORD color;

    FVERTEX3D_LINE()
        :x(0)
        ,y(0)
        ,z(0)
        ,color(0xFFFFFFFF)
    {}
    bool operator == (const FVERTEX3D_LINE& r)
    {
        return (x==r.x && y==r.y && z==r.z && color==r.color);
    }
};
const DWORD FVERTEX3D_LINE_STRIDE = sizeof(FVERTEX3D_LINE);
const EF_FVF FVERTEX3D_LINE_FVF = (EF_FVF)(eFVF_XYZ|eFVF_DIFFUSE);


//----------------------------------------------------------------
// 3D
//----------------------------------------------------------------
struct FVERTEX3D_RIBBON
{
    FDECLARE_STRUCT(FVERTEX3D_RIBBON)

    float x, y, z;
    float u, v;

    FVERTEX3D_RIBBON()
        :x(0)
        ,y(0)
        ,z(0)
        ,u(0)
        ,v(0)
    {}
    bool operator == (const FVERTEX3D_RIBBON& r)
    {
        if (fabsf(x  - r.x ) > 0.01f)
            return false;
        if (fabsf(y  - r.y ) > 0.01f)
            return false;
        if (fabsf(z  - r.z ) > 0.01f)
            return false;
        return (u == r.u && v == r.v);
    }
};
const DWORD FVERTEX3D_RIBBON_STRIDE = sizeof(FVERTEX3D_RIBBON);
const EF_FVF FVERTEX3D_RIBBON_FVF = (EF_FVF)(eFVF_XYZ|eFVF_TEX1);


//----------------------------------------------------------------
// 3D position
//----------------------------------------------------------------
struct FVERTEX3D_POSITION
{
    FDECLARE_STRUCT(FVERTEX3D_POSITION)

#if FUEL_RENDER_STREAM_FLOAT16
    FFLOAT16 x, y, z, w;
#else
    float x, y, z;
#endif

    FVERTEX3D_POSITION()
        :x(0)
        ,y(0)
        ,z(0)
#if FUEL_RENDER_STREAM_FLOAT16
        ,w(0)
#endif
    {}
    FVERTEX3D_POSITION(float fx, float fy, float fz)
        :x(fx)
        ,y(fy)
        ,z(fz)
#if FUEL_RENDER_STREAM_FLOAT16
        ,w(0)
#endif
    {}
    FINLINE bool operator == (const FVERTEX3D_POSITION& r)
    {
#if FUEL_RENDER_STREAM_FLOAT16
        return FMemcmp(this, &r, sizeof(r)) == 0;
#else
        if (FAbsF(x - r.x ) > 0.01f)
            return false;
        if (FAbsF(y - r.y ) > 0.01f)
            return false;
        if (FAbsF(z - r.z ) > 0.01f)
            return false;
#endif
        return true;
    }
    FINLINE void set(float _x, float _y, float _z)
    {
#if FUEL_RENDER_STREAM_FLOAT16
        x = FFLOAT16(_x);
        y = FFLOAT16(_y);
        z = FFLOAT16(_z);
#else
        x = _x;
        y = _y;
        z = _z;
#endif
    }
    FINLINE void get(FVECTOR3& o)
    {
        o.x = x, o.y = y, o.z = z;
    }
};
const DWORD FVERTEX3D_POSITION_STRIDE = sizeof(FVERTEX3D_POSITION);


//----------------------------------------------------------------
// 3D normal
//----------------------------------------------------------------
struct FVERTEX3D_NORMAL
{
    FDECLARE_STRUCT(FVERTEX3D_NORMAL)

#if FUEL_RENDER_STREAM_FLOAT16
    FFLOAT16 nx, ny, nz, nw;
#else
    float nx, ny, nz;
#endif

    FVERTEX3D_NORMAL()
        :nx(0)
        ,ny(0)
        ,nz(1)
#if FUEL_RENDER_STREAM_FLOAT16
        ,nw(0)
#endif
    {}
    FINLINE bool operator == (const FVERTEX3D_NORMAL& r)
    {
#if FUEL_RENDER_STREAM_FLOAT16
        return FMemcmp(this, &r, sizeof(r)) == 0;
#else
        if (FAbsF(nx - r.nx ) > 0.01f)
            return false;
        if (FAbsF(ny - r.ny ) > 0.01f)
            return false;
        if (FAbsF(nz - r.nz ) > 0.01f)
            return false;
#endif
        return true;
    }
    FINLINE void set(float _nx, float _ny, float _nz)
    {
#if FUEL_RENDER_STREAM_FLOAT16
        nx = FFLOAT16(_nx);
        ny = FFLOAT16(_ny);
        nz = FFLOAT16(_nz);
#else
        nx = _nx;
        ny = _ny;
        nz = _nz;
#endif
    }
    FINLINE void get(FVECTOR3& o)
    {
        o.x = nx, o.y = ny, o.z = nz;
    }
};
const DWORD FVERTEX3D_NORMAL_STRIDE = sizeof(FVERTEX3D_NORMAL);


//----------------------------------------------------------------
// 3D color
//----------------------------------------------------------------
struct FVERTEX3D_COLOR
{
    FDECLARE_STRUCT(FVERTEX3D_COLOR)

    DWORD color;

    FVERTEX3D_COLOR()
        :color(0xffffffff)
    {}
    FINLINE bool operator == (const FVERTEX3D_COLOR& r)
    {
        return color == r.color;
    }
};
const DWORD FVERTEX3D_COLOR_STRIDE = sizeof(FVERTEX3D_COLOR);


//----------------------------------------------------------------
// 3D uv
//----------------------------------------------------------------
struct FVERTEX3D_UV
{
    FDECLARE_STRUCT(FVERTEX3D_UV)

#if FUEL_RENDER_STREAM_FLOAT16
    FFLOAT16 u, v;
#else
    float u, v;
#endif

    FVERTEX3D_UV()
        :u(0)
        ,v(0)
    {}
    FINLINE bool operator == (const FVERTEX3D_UV& r)
    {
        return (u==r.u && v==r.v);
    }
    FINLINE void set(float _u, float _v)
    {
#if FUEL_RENDER_STREAM_FLOAT16
        u = FFLOAT16(_u);
        v = FFLOAT16(_v);
#else
        u = _u;
        v = _v;
#endif
    }
    FINLINE void get(FVECTOR2& o)
    {
        o.x = u, o.y = v;
    }
};
const DWORD FVERTEX3D_UV_STRIDE = sizeof(FVERTEX3D_UV);


//----------------------------------------------------------------
// 3D tangent
//----------------------------------------------------------------
struct FVERTEX3D_TANGENT
{
    FDECLARE_STRUCT(FVERTEX3D_TANGENT)

#if FUEL_RENDER_STREAM_FLOAT16
    FFLOAT16 tx, ty, tz, tw;
#else
    float tx, ty, tz;
#endif

    FVERTEX3D_TANGENT()
        :tx(1)
        ,ty(0)
        ,tz(0)
#if FUEL_RENDER_STREAM_FLOAT16
        ,tw(0)
#endif
    {}
    FINLINE bool operator == (const FVERTEX3D_TANGENT& r)
    {
#if FUEL_RENDER_STREAM_FLOAT16
        return FMemcmp(this, &r, sizeof(r)) == 0;
#else
        if (FAbsF(tx - r.tx ) > 0.01f)
            return false;
        if (FAbsF(ty - r.ty ) > 0.01f)
            return false;
        if (FAbsF(tz - r.tz ) > 0.01f)
            return false;
#endif
        return true;
    }
    FINLINE void set(float _tx, float _ty, float _tz)
    {
#if FUEL_RENDER_STREAM_FLOAT16
        tx = FFLOAT16(_tx);
        ty = FFLOAT16(_ty);
        tz = FFLOAT16(_tz);
#else
        tx = _tx;
        ty = _ty;
        tz = _tz;
#endif
    }
};
const DWORD FVERTEX3D_TANGENT_STRIDE = sizeof(FVERTEX3D_TANGENT);


//----------------------------------------------------------------
// 3D blend index
//----------------------------------------------------------------
struct FVERTEX3D_BLENDIDX
{
    FDECLARE_STRUCT(FVERTEX3D_BLENDIDX)

    BYTE bidx[4];

    FVERTEX3D_BLENDIDX()
    {
        memset(bidx, 0xFF, sizeof(bidx));
    }
    FINLINE bool operator == (const FVERTEX3D_BLENDIDX& r)
    {
        return (FMemcmp(bidx, r.bidx, sizeof(bidx)) == 0);
    }
    FINLINE BYTE Add(BYTE vl)
    {
        for (size_t i = 0; i < 4; ++i)
        {
            if (bidx[i] == 0xFF)
            {
                bidx[i] = vl;
                return (BYTE)i;
            }
        }
        return 0xFF;
    }
};
const DWORD FVERTEX3D_BLENDIDX_STRIDE = sizeof(FVERTEX3D_BLENDIDX);


//----------------------------------------------------------------
// 3D  blend weight (max 2 bone)
//----------------------------------------------------------------
struct FVERTEX3D_BLENDWEIGHT2
{
    FDECLARE_STRUCT(FVERTEX3D_BLENDWEIGHT2)

#if FUEL_RENDER_STREAM_FLOAT16
    FFLOAT16 weight[2];
#else
    float weight[2];
#endif

    FVERTEX3D_BLENDWEIGHT2()
    {
        memset(weight, 0, sizeof(weight));
    }
    FINLINE bool operator == (const FVERTEX3D_BLENDWEIGHT2& r)
    {
        return (FMemcmp(weight, r.weight, sizeof(weight)) == 0);
    }
    FINLINE void set(BYTE idx, float vl)
    {
#if FUEL_RENDER_STREAM_FLOAT16
        weight[idx] = FFLOAT16(vl);
#else
        weight[idx] = vl;
#endif
    }
};
const DWORD FVERTEX3D_BLENDWEIGHT2_STRIDE = sizeof(FVERTEX3D_BLENDWEIGHT2);


//----------------------------------------------------------------
// 3D  blend weight (max 4 bone)
//----------------------------------------------------------------
struct FVERTEX3D_BLENDWEIGHT4
{
    FDECLARE_STRUCT(FVERTEX3D_BLENDWEIGHT4)

#if FUEL_RENDER_STREAM_FLOAT16
    FFLOAT16 weight[4];
#else
    float weight[4];
#endif

    FVERTEX3D_BLENDWEIGHT4()
    {
        memset(weight, 0, sizeof(weight));
    }
    FINLINE bool operator == (const FVERTEX3D_BLENDWEIGHT4& r)
    {
        return (FMemcmp(weight, r.weight, sizeof(weight)) == 0);
    }
    FINLINE void set(BYTE idx, float vl)
    {
#if FUEL_RENDER_STREAM_FLOAT16
        weight[idx] = FFLOAT16(vl);
#else
        weight[idx] = vl;
#endif
    }
};
const DWORD FVERTEX3D_BLENDWEIGHT4_STRIDE = sizeof(FVERTEX3D_BLENDWEIGHT4);


//----------------------------------------------------------------
// Index format
//----------------------------------------------------------------
typedef WORD FINDEX;

const DWORD FINDEX_STRIDE = sizeof(FINDEX);


//----------------------------------------------------------------
// 2D Default Index Define
//----------------------------------------------------------------
const FINDEX FINDEX_DEFAULT_2D[6] = {0, 1, 2, 2, 1, 3};


//----------------------------------------------------------------
// 3D Index Buffer
//----------------------------------------------------------------
struct FFACE3D
{
    FDECLARE_STRUCT(FFACE3D)

    FINDEX idx[3];

    FFACE3D()
    {
        idx[0] = idx[1] = idx[2] = 0;
    }
};
const DWORD FFACE3D_STRIDE = sizeof(FFACE3D);


//----------------------------------------------------------------
// 
//----------------------------------------------------------------
struct FVERTEXELEMENT
{
    WORD    Stream;     // Stream index
    WORD    Offset;     // Offset in the stream in bytes
    BYTE    Type;       // Data type
    BYTE    Method;     // Processing method
    BYTE    Usage;      // Semantics
    BYTE    UsageIndex; // Semantic index
};


#pragma pack(pop)


typedef FVector< FVERTEX2D >            FV_VERTEX2D;
typedef FVector< FVERTEX2D_LINE >       FV_VERTEX2D_LINE;
typedef FVector< FVERTEX3D_SPRITE >     FV_VERTEX3D_SPRITE;
typedef FVector< FVERTEX3D_LINE >       FV_VERTEX3D_LINE;
typedef FVector< FVERTEX3D_RIBBON >     FV_VERTEX3D_RIBBON;
typedef FVector< FVERTEX3D_POSITION >   FV_VERTEX3D_POSITION;
typedef FVector< FVERTEX3D_NORMAL >     FV_VERTEX3D_NORMAL;
typedef FVector< FVERTEX3D_COLOR >      FV_VERTEX3D_COLOR;
typedef FVector< FVERTEX3D_UV >         FV_VERTEX3D_UV;
typedef FVector< FVERTEX3D_TANGENT >    FV_VERTEX3D_TANGENT;
typedef FVector< FVERTEX3D_BLENDIDX >   FV_VERTEX3D_BLENDIDX;
typedef FVector< FVERTEX3D_BLENDWEIGHT2 >   FV_VERTEX3D_BLENDWEIGHT2;
typedef FVector< FVERTEX3D_BLENDWEIGHT4 >   FV_VERTEX3D_BLENDWEIGHT4;
typedef FVector< FINDEX >               FV_INDEX;
typedef FVector< FFACE3D >              FV_FACE3D;
typedef FVector< FVERTEXELEMENT >       FVVERTEXELEMENT;